/*
 * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "interceptor/screen_unlock_interceptor.h"

#include "ability_record.h"
#include "ability_util.h"
#include "extension_config.h"
#include "event_report.h"
#include "parameters.h"
#include "start_ability_utils.h"
#include "startup_util.h"
#ifdef SUPPORT_SCREEN
#ifdef ABILITY_RUNTIME_SCREENLOCK_ENABLE
#include "screenlock_manager.h"
#endif // ABILITY_RUNTIME_SCREENLOCK_ENABLE
#endif

namespace OHOS {
namespace AAFwk {
void ScreenUnlockInterceptor::RecordExtensionEventWhenScreenUnlock(const AbilityInterceptorParam &param,
    const AppExecFwk::AbilityInfo &targetAbilityInfo)
{
#ifdef SUPPORT_SCREEN
#ifdef ABILITY_RUNTIME_SCREENLOCK_ENABLE
    EventInfo eventInfo;
    eventInfo.bundleName = param.want.GetElement().GetBundleName();
    eventInfo.abilityName = param.want.GetElement().GetAbilityName();
    eventInfo.moduleName = "StartAbilityScreenUnlock";
    if (eventInfo.bundleName.empty()) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "bundleName empty, dont report");
        return;
    }
    if (targetAbilityInfo.type == AppExecFwk::AbilityType::EXTENSION &&
        DelayedSingleton<ExtensionConfig>::GetInstance()->IsScreenUnlockAllowAbility(
            targetAbilityInfo.extensionTypeName, eventInfo.bundleName, eventInfo.abilityName)) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "ability: %{public}s/%{public}s is in allowList, dont report",
            eventInfo.bundleName.c_str(), eventInfo.abilityName.c_str());
        return;
    }
    if (!OHOS::ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) {
        return;
    }
    std::string callerBundleName;
    if (param.callerToken) {
        auto callAbilityRecord = Token::GetAbilityRecordByToken(param.callerToken);
        if (callAbilityRecord) {
            callerBundleName = callAbilityRecord->GetAbilityInfo().bundleName;
        }
    }
    int32_t callerUid = IPCSkeleton::GetCallingUid();
    eventInfo.callerBundleName = callerBundleName.empty() ? std::to_string(callerUid) : callerBundleName;
    TAG_LOGD(AAFwkTag::ABILITYMGR, "report screen unlock ability: %{public}s/%{public}s:%{public}s",
        eventInfo.bundleName.c_str(), eventInfo.abilityName.c_str(), eventInfo.callerBundleName.c_str());
    EventReport::SendStartAbilityOtherExtensionEvent(EventName::START_ABILITY_OTHER_EXTENSION, eventInfo);
#endif
#endif
}

ErrCode ScreenUnlockInterceptor::DoProcess(AbilityInterceptorParam param)
{
    // get target application info
    AppExecFwk::AbilityInfo targetAbilityInfo;
    if (StartAbilityUtils::startAbilityInfo != nullptr) {
        targetAbilityInfo = StartAbilityUtils::startAbilityInfo->abilityInfo;
    } else {
        QueryTargetAbilityInfo(param, targetAbilityInfo);
        if (targetAbilityInfo.applicationInfo.name.empty() ||
            targetAbilityInfo.applicationInfo.bundleName.empty()) {
            TAG_LOGD(AAFwkTag::ABILITYMGR, "Cannot find targetAbilityInfo, element uri: %{public}s/%{public}s",
                param.want.GetElement().GetBundleName().c_str(), param.want.GetElement().GetAbilityName().c_str());
            return ERR_OK;
        }
    }
    if (targetAbilityInfo.applicationInfo.allowAppRunWhenDeviceFirstLocked) {
        RecordExtensionEventWhenScreenUnlock(param, targetAbilityInfo);
        return ERR_OK;
    }
#ifdef SUPPORT_SCREEN
#ifdef ABILITY_RUNTIME_SCREENLOCK_ENABLE
    if (!OHOS::ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) {
        return ERR_OK;
    }
#endif // ABILITY_RUNTIME_SCREENLOCK_ENABLE
#endif
    if (targetAbilityInfo.applicationInfo.isSystemApp &&
        targetAbilityInfo.type != AppExecFwk::AbilityType::EXTENSION) {
        EventInfo eventInfo;
        eventInfo.bundleName = targetAbilityInfo.applicationInfo.bundleName;
        eventInfo.moduleName = "StartScreenUnlock";
        EventReport::SendStartAbilityOtherExtensionEvent(EventName::START_ABILITY_OTHER_EXTENSION, eventInfo);
        return ERR_OK;
    }
    if (targetAbilityInfo.type == AppExecFwk::AbilityType::EXTENSION &&
        !DelayedSingleton<ExtensionConfig>::GetInstance()->IsScreenUnlockIntercept(
            targetAbilityInfo.extensionTypeName, targetAbilityInfo.applicationInfo.isSystemApp,
            targetAbilityInfo.applicationInfo.bundleName)) {
        RecordExtensionEventWhenScreenUnlock(param, targetAbilityInfo);
        return ERR_OK;
    }
    TAG_LOGE(AAFwkTag::ABILITYMGR, "no startup before device first unlock");
    return ERR_BLOCK_START_FIRST_BOOT_SCREEN_UNLOCK;
}

void ScreenUnlockInterceptor::QueryTargetAbilityInfo(const AbilityInterceptorParam &param,
    AppExecFwk::AbilityInfo &targetAbilityInfo)
{
    auto bundleMgrHelper = AbilityUtil::GetBundleManagerHelper();
    if (bundleMgrHelper == nullptr) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "The bundleMgrHelper is nullptr.");
        return;
    }
    IN_PROCESS_CALL_WITHOUT_RET(bundleMgrHelper->QueryAbilityInfo(param.want,
        AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_APPLICATION, param.userId, targetAbilityInfo));
    if (!targetAbilityInfo.applicationInfo.name.empty() && !targetAbilityInfo.applicationInfo.bundleName.empty()) {
        return;
    }

    std::vector<AppExecFwk::ExtensionAbilityInfo> extensionInfos;
    IN_PROCESS_CALL(bundleMgrHelper->QueryExtensionAbilityInfos(param.want,
        AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_WITH_APPLICATION, param.userId, extensionInfos));
    if (extensionInfos.size() <= 0) {
        TAG_LOGD(AAFwkTag::ABILITYMGR, "extensionInfo empty");
        return;
    }
    AbilityRuntime::StartupUtil::InitAbilityInfoFromExtension(extensionInfos.front(), targetAbilityInfo);
}
} // namespace AAFwk
} // namespace OHOS